home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / basics / draganddrop shell / dtsqtutilities.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  58.1 KB  |  1,789 lines

  1. /*
  2.     File:        DTSQTUtilities.c
  3.  
  4.     Contains:    QuickTime functions.
  5.  
  6.     Written by:     
  7.  
  8.     Copyright:    Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/28/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24.  
  25. // INCLUDES
  26. #include "DTSQTUtilities.h"
  27.  
  28.  
  29. // MOVIE TOOLBOX FUNCTIONS
  30.  
  31. /*______________________________________________________________________
  32.     QTUIsQuickTimeInstalled - Test if QuickTime is installed.
  33.  
  34. pascal Boolean    QTUIsQuickTimeInstalled(void) 
  35.  
  36. DESCRIPTION
  37.     InitQuickTime will test if QuickTime is present. We are not interested in the QuickTime
  38.     version.
  39.  
  40. ISSUES
  41.     You could combine this function with the QTUGetQTVersion so you could also fetch the
  42.     version level of QT at the same time.
  43. */
  44.  
  45. pascal Boolean QTUIsQuickTimeInstalled(void) 
  46. {
  47.     OSErr     anErr = noErr;
  48.     long         qtVersion;
  49.  
  50.     anErr = Gestalt(gestaltQuickTime, &qtVersion); DebugAssert(anErr == noErr);
  51.     if (anErr != noErr)
  52.         return false;        // no QT present
  53.     else
  54.         return true;
  55. }
  56.  
  57.  
  58. /*______________________________________________________________________
  59.     QTUIsQuickTimeCFMInstalled - Test if the QuickTime CFM libraries are installed and in the 
  60.     right place.
  61.  
  62. pascal Boolean    QTUIsQuickTimeCFMInstalled(void) 
  63.  
  64. DESCRIPTION
  65.     QTUIsQuickTimeCFMInstalled will test if the CFM QuickTime libraries are present (QuickTime 
  66.     PowerPlug, for instance), and if the libraries are still present (this because the libraries are 
  67.     registered once when Gestalt finds then during runtime, and the end user might delete these, 
  68.     or move them to another location later)(.
  69. */
  70.  
  71. #ifdef powerc
  72. pascal Boolean QTUIsQuickTimeCFMInstalled(void) 
  73. {
  74.     OSErr     anErr = noErr;
  75.     long         qtFeatures = 0L; 
  76.  
  77. // Test if the library is registered.
  78.     anErr = Gestalt(gestaltQuickTimeFeatures, &qtFeatures); DebugAssert(anErr == noErr);
  79.     
  80.     if (!(  (anErr == noErr)  &&  (qtFeatures & (1 << gestaltPPCQuickTimeLibPresent))  )) // not true
  81.           return false;
  82.           
  83. // Test if a function is available (the library is not moved from the Extension folder),  this is the 
  84. // trick to be used concerning testing if a function is available via CFM.
  85.  
  86.     if   ( ! CompressImage )
  87.         return false;     
  88.     else 
  89.         return true;
  90. }
  91. #endif // powerc
  92.  
  93.  
  94. /*______________________________________________________________________
  95.     QTUGetQTVersion - Return the current QuickTime version number.
  96.  
  97. pascal long QTUGetQTVersion()
  98.  
  99. DESCRIPTION
  100.     QTUGetQTVersion is a simple function that will return the current QuickTime version number,
  101.     and if QuickTime is not installed it will return 0L.  The high order word defines the version number, 
  102.     for instance 0x0161 defines version 1.6.1.
  103.     
  104.     You could also directly assign a boolean value stating if a certain version is true by using this
  105.     kind of an expression:
  106.     
  107.     Boolean gHasQT2.0 = (( QTUGetQTVersion() >>  16) & 0xFFFF) >= 0x200;
  108.     
  109. EXAMPLE
  110.     if( (QTUGetQTVersion() >> 16) < 0x150 ) return; // need to work with QT 1.5 or higher.
  111. */
  112.  
  113. pascal long QTUGetQTVersion()
  114. {
  115.     long version = 0L;
  116.     
  117.     if(Gestalt(gestaltQuickTime, &version) == noErr)
  118.         return version;
  119.     else
  120.         return 0L;
  121. }
  122.  
  123.  
  124. /*______________________________________________________________________
  125.     QTUAreQuickTimeMusicInstrumentsPresent - Test if the Musical Instruments Extension is 
  126.     installed.
  127.  
  128. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  129.  
  130. DESCRIPTION
  131.     QTUAreQuickTimeMusicInstrumentsPresent tests if the QuickTime Musical Instruments
  132.     extension (actually a component) is registered. If this is not the case, then most likely
  133.     the extension was never placed into the extension folder, and the end user should be
  134.     informed about this.
  135. */
  136.  
  137. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  138. {
  139.     ComponentDescription aCD;
  140.     
  141.     aCD.componentType = 'inst';
  142.     aCD.componentSubType = 'ss  ';
  143.     aCD.componentManufacturer = 'appl';
  144.     
  145.     if(FindNextComponent((Component)0, &aCD) != NULL)
  146.         return true;
  147.     else
  148.         return false;
  149. }
  150.  
  151.  
  152. /*______________________________________________________________________
  153.      QTUPrerollMovie - Preroll the movie before you start the movie.
  154.  
  155. pascal OSErr QTUPrerollMovie(Movie theMovie)
  156.  
  157. theMovie                the destination movie for this operation
  158.  
  159. DESCRIPTION
  160.     QTUPrerollMovie will get the movie time,  duration and preferred rate, and Preroll the movie 
  161.     based on this information. Note that StartMovie already does a PrerollMovie so in that case this 
  162.     is not needed, this is also true of the standard controller that handles the start of movie
  163.     when the keyboard or mouse is used.
  164. */
  165.  
  166. pascal OSErr QTUPrerollMovie(Movie theMovie) 
  167. {
  168.     OSErr                anErr = noErr;
  169.     TimeValue         aTimeValue;
  170.     TimeValue            aMovieDur;
  171.     Fixed                 aPreferredRate;
  172.  
  173.     aTimeValue          = GetMovieTime(theMovie, NULL);
  174.     aMovieDur         = GetMovieDuration(theMovie);
  175.     aPreferredRate  = GetMoviePreferredRate(theMovie);
  176.  
  177.     if(aTimeValue == aMovieDur) aTimeValue = 0;
  178.  
  179.     anErr = PrerollMovie(theMovie, aTimeValue, aPreferredRate); DebugAssert(anErr == noErr);
  180.     
  181.     return anErr;
  182. }
  183.  
  184.  
  185. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock);
  186.  
  187.  
  188. /*______________________________________________________________________
  189.     QTUGetMovie - Get a Movie from a specific file.
  190.  
  191. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  192.  
  193. theFSSpec                the specific FSSpec used, if NULL the system will use a standard dialog
  194.                             box for the end user to select a file
  195. theRefNum            this is the specific file ref num we want to use later
  196. theResID                this is the specific resource ID we want to use later
  197.  
  198. DESCRIPTION
  199.     QTUGetMovie will get a movie resource out from a specified file, if the FSSpec is not provided
  200.     then the function will use a StandardGetFilePreview to select the movie.
  201. */
  202.  
  203. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  204. {
  205.     OSErr                    anErr = noErr;
  206.     SFTypeList            aTypeList = {MovieFileType, 0, 0, 0};
  207.     StandardFileReply    aReply;
  208.     Movie                    aMovie = NULL;
  209.  
  210. // If we are provided with an FSSpec then use it, otherwise do a standardgetfile dialog box and 
  211. // ask the end user to get it.
  212.     if(theFSSpec == NULL || theFSSpec->vRefNum == 0)
  213.     {    
  214.         StandardGetFilePreview( NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply);
  215.         if(! aReply.sfGood)
  216.             return NULL;
  217.         
  218.         *theFSSpec = aReply.sfFile;
  219.     }
  220.  
  221.     // We should have now a usable FSSpec, just double check this once again before continuing.
  222.     DebugAssert(theFSSpec != NULL); if(theFSSpec == NULL) return NULL;
  223.     
  224.     anErr = OpenMovieFile(theFSSpec, theRefNum, fsRdPerm); DebugAssert(anErr == noErr);
  225.     // Note we define fsRdPerm, you could use another flag if needed.
  226.  
  227.     if(anErr == noErr)
  228.     {
  229.         Str255    aMovieName;
  230.         Boolean    wasChanged;
  231.         
  232.         *theResID = 0;                    // want first movie
  233.         
  234.         anErr = NewMovieFromFile(&aMovie, *theRefNum, theResID,
  235.                                                     aMovieName, newMovieActive, &wasChanged);
  236.  
  237.         DebugAssert(anErr == noErr);
  238.  
  239.         CloseMovieFile(*theRefNum);
  240.     }
  241.     
  242.     if(anErr != noErr)
  243.         return NULL;
  244.     else
  245.         return aMovie;
  246. }
  247.  
  248.  
  249. /*______________________________________________________________________
  250.     QTUSimpleGetMovie - Get a Movie from a specific file (simpler version)
  251.  
  252. pascal OSErr QTUSimpleGetMovie(Movie *theMovie)
  253.  
  254. theMovie                will contain the selected movie when function exits.
  255.  
  256. DESCRIPTION
  257.     QTUSimpleGetMovie is a simplified version of getting a movie from a file, no need for
  258.     returning refnums, res IDs of keeping track of FSSpecs (compared with QTUGetMovie)
  259. */
  260.  
  261. pascal OSErr QTUSimpleGetMovie(Movie *theMovie)
  262. {
  263.     OSErr                     anErr = noErr;
  264.     SFTypeList            aTypeList = {MovieFileType, 0, 0, 0};
  265.     short                    resFile = 0;
  266.     short                    resID = 0;
  267.     StandardFileReply    aReply;
  268.     Str255                    movieName;
  269.     Boolean                    wasChanged;
  270.  
  271.     StandardGetFilePreview(NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply);
  272.     if(aReply.sfGood)
  273.     {
  274.         anErr = OpenMovieFile(&aReply.sfFile, &resFile, fsRdPerm); DebugAssert(anErr == noErr);
  275.         if(anErr == noErr)
  276.         {
  277.             anErr = NewMovieFromFile(theMovie, resFile, &resID, movieName, newMovieActive, &wasChanged);
  278.             DebugAssert(anErr == noErr);
  279.  
  280.             CloseMovieFile(resFile);
  281.         }
  282.     }
  283.     return anErr;
  284. }
  285.  
  286.  
  287. /*______________________________________________________________________
  288.     QTUFileFilter - Skeleton file filter to be used with various MovieToolbox standard dialog utilities.
  289.  
  290. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock)
  291.  
  292. theParamBlock        specifies a particular ParmBlockPtr
  293.  
  294. DESCRIPTION
  295.     QTUFileFilter is a skeleton file filter to be used with various MovieToolbox standard dialog utilities
  296.     The function will return a boolean false if it encounters any errors from the Movie toolbox.
  297. */
  298.  
  299. pascal Boolean QTUFileFilter(ParmBlkPtr /*theParamBlock */)
  300. {
  301.     return false;
  302. }
  303.  
  304.  
  305. /*______________________________________________________________________
  306.       QTUSaveMovie - Save and flatten a movie resource into a  file.
  307.  
  308. pascal OSErr QTUSaveMovie(Movie theMovie)
  309.  
  310. theMovie            defines the movie to be saved into a file
  311.  
  312. DESCRIPTION
  313.     QTUSaveMovie will provide a user dialog asking for a file name, and will then save the movie
  314.     into this file. Note that this function will also automatically flatten the movie so that  it's 
  315.     self-contained, and also make it cross-platform (by adding any possible resource forks to
  316.     the end of the data fork. The default name of the movie is also NEWMOVIE.MOV, this reflects
  317.     the way movie file names should be named for cross-platform support (Windows). The default
  318.     creator type is also 'TVOD' so that MoviePlayer will be the default application that opens the
  319.     movie file. If there's an existing movie file with the same name, it will be deleted.
  320. */
  321.  
  322.  
  323. pascal OSErr QTUSaveMovie(Movie theMovie)
  324. {
  325.     OSErr                     anErr = noErr;
  326.     StandardFileReply    anSFReply;
  327.     
  328.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  329.     
  330.     StandardPutFile("\pSave Movie as:" , "\pNEWMOVIE.MOV", &anSFReply); 
  331.     if(anSFReply.sfGood)
  332.     {
  333.  
  334.         FlattenMovieData(theMovie, flattenAddMovieToDataFork, &anSFReply.sfFile, 
  335.                                         'TVOD', smSystemScript, createMovieFileDeleteCurFile );
  336.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  337.     }
  338.         return anErr;
  339. }
  340.  
  341.  
  342. /*______________________________________________________________________
  343.     QTUFlattenMovieFile - Flatten a movie into a specified file.
  344.  
  345. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  346.  
  347. theMovie                defines the movie to be flattened
  348. theFile                    defines the target file
  349.  
  350. DESCRIPTION
  351.     FlattenMovie file will take an existing movie, flatten it into a temp file, and then move the
  352.     contents of the temp file into the specified FSSpec. This because there are cases where we 
  353.     can't flatten a movie in place. We will use TickCount as a temp file name.    
  354.     
  355.     Note that we need to dispose the movie inside this function? Why? Well, the file is open as
  356.     long as there's a pointer to it from the movie resource. And we need to delete the original 
  357.     movie file as part of the operation of swapping the files. 
  358. */
  359.  
  360. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  361. {
  362.     OSErr         anErr = noErr;
  363.     FSSpec         tempFile;
  364.     Str255     tempFileName;
  365.     
  366.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  367.     
  368.     // Create the needed temp file.
  369.     NumToString(TickCount(), tempFileName);
  370.         anErr = FSMakeFSSpec(theFile->vRefNum, theFile->parID, tempFileName, &tempFile);
  371.     if(anErr != fnfErr) return anErr;
  372.     
  373.     // Flatten the movie.
  374.     FlattenMovie(theMovie, flattenAddMovieToDataFork, &tempFile, 'TVOD', smSystemScript, 
  375.                             createMovieFileDeleteCurFile, 0, NULL);
  376.     anErr = GetMoviesError();
  377.     if(anErr != noErr)
  378.     {
  379.         FSpDelete(&tempFile);        // remove the temp file
  380.         return anErr;
  381.     }
  382.     
  383.     DisposeMovie(theMovie);
  384.     anErr = FSpDelete(theFile);  ReturnIfError(anErr);
  385.     anErr = FSpRename(&tempFile, theFile->name); ReturnIfError(anErr);
  386.     
  387.     return anErr;
  388. }
  389.  
  390.  
  391. // TRACKS AND MEDIA
  392.  
  393. /*______________________________________________________________________
  394.     QTUMediaTypeInTrack - Check if a particular media type is present in the movie.
  395.  
  396. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  397.  
  398. theMovie                    movie to be tested about the media type
  399. theMediaType            media type we want to test about
  400.  
  401. DESCRIPTION
  402.     QTUMediaTypeInTrack could be used to scan if a possible media type is present in the movie 
  403.     (video,sound, other media types).
  404. */
  405.  
  406. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  407. {
  408.     Track         aTrack = NULL;
  409.     long            aTrackCount = 0;
  410.     long            index;
  411.     OSType        aMediaType;
  412.     Boolean        haveMediaType = false;
  413.     
  414.     aTrackCount = GetMovieTrackCount(theMovie);
  415.     if(aTrackCount == 0)
  416.         return false;                // no tracks in movie
  417.     
  418.     for(index = 1; index <= aTrackCount; index++)
  419.     {
  420.         aTrack = GetMovieIndTrack(theMovie, index);
  421.         GetMediaHandlerDescription( GetTrackMedia(aTrack), &aMediaType, NULL, NULL);
  422.         
  423.         haveMediaType = ( aMediaType == theMediaType);
  424.         if(haveMediaType == true)
  425.             return true;
  426.     }
  427.     return false;            // didn't find the media type track in the movie
  428. }
  429.  
  430.  
  431. /*______________________________________________________________________
  432.     QTUGetTrackRect - Get the Rect of a specified  track.
  433.  
  434. pascal Rect QTUGetTrackRect(Track theTrack)
  435.  
  436. theTrack                track we are interested in concerning the rect information
  437.  
  438. DESCRIPTION
  439.     QTUMediaTypeInTrack will take a (visual) track and return the track's Rect boundaries that 
  440.     could be used later for various calculations of the visual track geometries. Note that
  441.     this Rect is meaningful with video tracks (and any other tracks that have geometrical
  442.     dimensions, otherwise this function will return a rect with zero values.
  443. */
  444.  
  445. pascal OSErr QTUGetTrackRect(Track theTrack, Rect *theRect)
  446. {
  447.     OSErr    anErr = noErr;
  448.     Fixed    aTrackHeight;
  449.     Fixed    aTrackWidth;
  450.  
  451.     theRect->top = 0; theRect->left = 0; theRect->bottom = 0; theRect->right = 0;
  452.     
  453.     DebugAssert(theTrack != NULL);
  454.     if(theTrack == NULL)
  455.         return invalidTrack;
  456.         
  457.     GetTrackDimensions(theTrack, &aTrackHeight, &aTrackWidth);
  458.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  459.     if(anErr != noErr)
  460.         return anErr;
  461.     
  462.     theRect->right = Fix2Long(aTrackWidth);
  463.     theRect->bottom = Fix2Long(aTrackHeight);
  464.     
  465.     return anErr;
  466. }
  467.  
  468.  
  469. /*______________________________________________________________________
  470.     QTUGetVideoMediaPixelDepth - Return the pixel depth of the video media (sample).
  471.  
  472. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  473.  
  474. theMedia            visual media we want to test concerning pixel depths
  475. index                   index into the media sample we are interested in
  476.  
  477. DESCRIPTION
  478.     QTUGetVideoMediaPixelDepth will take a specified video media and an index into the media 
  479.     samples, and look up the pixel depth for the video sample.
  480. */
  481.  
  482. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  483. {
  484.     OSErr                                 anErr = noErr;
  485.     short                                 aPixelDepth;
  486.     SampleDescriptionHandle    anImageDesc = NULL;
  487.     OSType                                 mediaType;
  488.     
  489.     DebugAssert(theMedia != NULL);
  490.     DebugAssert(index > 0);
  491.     
  492.     // Test if we are indeed dealing with video media.
  493.     GetMediaHandlerDescription(theMedia, &mediaType, NULL, NULL);
  494.     if(mediaType != VideoMediaType)
  495.         return 0;
  496.         
  497.     anImageDesc = (SampleDescriptionHandle)NewHandle(sizeof(Handle)); DebugAssert(anImageDesc != NULL);
  498.     if(anImageDesc == NULL)
  499.         return 0;
  500.     
  501.     GetMediaSampleDescription(theMedia, index, anImageDesc);
  502.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  503.     
  504.     aPixelDepth = (* (ImageDescriptionHandle)anImageDesc)->depth;
  505.     
  506.     DisposeHandle((Handle)anImageDesc);
  507.     
  508.     return aPixelDepth;
  509. }
  510.  
  511.  
  512. /*______________________________________________________________________
  513.     QTUCountMediaSamples - Count the amount of known media samples in a movie.
  514.  
  515. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  516.  
  517. theMovie                    the movie with the track(tracks).    
  518. theMediaType            the type of media we are interested in (video, sound and so on)
  519.  
  520. DESCRIPTION
  521.     QTUCountMediaSamples will take a specified movie and a media type, and calculate the amount 
  522.     of samples of this particular type. It could be used to find the total amount of video frames in a 
  523.     movie, or sound samples and so on.
  524.  
  525.     Note that if the movie is long, it will take a long time to go through all the samples, especially 
  526.     in the case of sound samples.
  527.  
  528. EXAMPLE:
  529.     nFrames = QTUCountMediaSamples(aSourceMovie, VideoMediaType); 
  530.  
  531. ISSUES
  532.     This function could be modified to count other types of samples by changing the flags definitions 
  533.     (nextTimeSyncSample for key frames and so on).
  534. */
  535.  
  536. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  537. {
  538.     long                 numFrames = 0;
  539.     short             flags = nextTimeMediaSample + nextTimeEdgeOK;
  540.     TimeValue        aDuration = 0;
  541.     TimeValue     theTime = 0;
  542.     
  543.     GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  544.     if(theTime == -1) return numFrames;
  545.  
  546.     flags = nextTimeMediaSample; // Don't include the  nudge after the first interesting time.
  547.     
  548.     while(theTime != -1)  // When the returned time equals -1, then there were no more interesting times.
  549.     {
  550.         numFrames++;
  551.         GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  552.     }
  553.     
  554.     return numFrames;
  555. }
  556.  
  557.  
  558. /*______________________________________________________________________
  559.     QTUGetDurationOfFirstMovieSample - Return the time value of the first sample of a certain 
  560.     media type.
  561.  
  562. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  563.  
  564. theMovie                        the movie with the media track
  565. theMediaType                specified media type (VideoMediaType, SoundMediaType and so on)
  566.  
  567. DESCRIPTION
  568.     QTUGetDurationOfFirstMovieSample returns the duration of the first sample of a certain media 
  569.     in the movie. If there is no such sample, the duration is 0.
  570.  
  571.     This function could be used in known cases where all the samples are assumed to be of the same 
  572.     duration. For instance in such cases the frame count could be calculated as:
  573.  
  574.     framecount =
  575.              GetMovieDuration(theMovie)/QTUGetDurationofFirstMovieSample(theMovie, VideoMediaType);
  576.  
  577. */
  578.  
  579. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  580. {
  581.     OSErr             anErr = noErr;
  582.     TimeValue        interestingDuration = 0;
  583.     short            timeFlags = nextTimeMediaSample+nextTimeEdgeOK;
  584.  
  585.     GetMovieNextInterestingTime(theMovie, timeFlags, (TimeValue)1, &theMediaType, 0, 
  586.                                                     fixed1, NULL, &interestingDuration);
  587.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  588.  
  589.     return interestingDuration;
  590. }
  591.  
  592.  
  593. /*______________________________________________________________________
  594.     QTUCountMaxSoundRate - Calculate the max sound data rate of a possible sound track
  595.    in the movie.
  596.  
  597. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  598.  
  599. theMovie                        the movie with the sound track(tracks).    
  600. theMaxSoundRate            the final returned value
  601.  
  602. DESCRIPTION
  603.     QTUCountMaxSoundRate (taken from the ConvertToMovieJr file) is a simple function that tries
  604.     to figure out the maximum sound track rate. This is done by looking at all of the sound tracks
  605.     in the source movie, and using the one with the highest sample rate (11khz, 22khz and so on),
  606.  
  607.     This number could then be used for calculating the maximum data rate by extracting the sound rate and 
  608.     this way we get a loose estimation how much is left for the video data rate.
  609.     
  610.     This is just an approximation, and a better function should take into account non-overlapping
  611.     sound tracks, stereo sound data rates, compressed sound tracks and so on.
  612. */
  613.  
  614. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  615. {
  616.     OSErr    anErr = noErr;
  617.     short     index, trackCount;
  618.     
  619.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  620.     *theMaxSoundRate = 0; // just for security we place this value in here
  621.     
  622.     trackCount = GetMovieTrackCount(theMovie);
  623.     
  624.     for(index = 1; index <= trackCount; index++)
  625.     {
  626.         OSType     aTrackType;
  627.         Track        aTrack = NULL;
  628.         Media        aMedia = NULL;
  629.         
  630.         aTrack = GetMovieIndTrack(theMovie, index);  DebugAssert(aTrack != NULL);
  631.         aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL);
  632.         anErr = GetMoviesError();  DebugAssert(anErr == noErr);
  633.         if(anErr != noErr) return anErr;
  634.         
  635.         GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
  636.         if(aTrackType == SoundMediaType)
  637.         {
  638.             long aRate;
  639.             SampleDescriptionHandle aDesc = NULL;
  640.             
  641.             aDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); DebugAssert(aDesc != NULL);
  642.             GetMediaSampleDescription(aMedia, 1, aDesc);
  643.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  644.             if(anErr != noErr)
  645.             {
  646.                 DisposeHandle((Handle)aDesc);
  647.                 continue;
  648.             }
  649.             
  650.             aRate = (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16;
  651.             if(aRate > *theMaxSoundRate)
  652.                 *theMaxSoundRate = aRate;
  653.         }
  654.     }
  655.     return anErr;
  656. }
  657.  
  658.  
  659.  
  660. /*______________________________________________________________________
  661.     QTUGetMovieFrameCount - Return the amount of frames in the movie based on frame rate estimate.
  662.  
  663. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  664.  
  665. theMovie                    the movie we want to calculate the frame count for.            
  666. theFrameRate            the expected frame rate of the movie
  667.  
  668. DESCRIPTION
  669.     QTUGetMovieFrameCount is a simple operation that takes into account the duration of the movie,
  670.     the time scale and a suggested frame rate, and based on this will calculate the 
  671.     amount of frames needed in the movie. We assume that the frame rate will be uniform in the movie.
  672. */
  673.  
  674. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  675. {
  676.     long         frameCount, duration, timescale;
  677.     float     exactFrames;
  678.     
  679.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  680.  
  681.     duration         = GetMovieDuration(theMovie);
  682.     timescale         = GetMovieTimeScale(theMovie);
  683.     exactFrames    = (float)duration * theFrameRate;
  684.     
  685.     frameCount    = exactFrames / timescale / 65536;
  686.     
  687.     if(frameCount == 0)
  688.         frameCount = 1;            // we got to have at least one frame
  689.     
  690.     return frameCount;
  691. }
  692.  
  693.  
  694. /*______________________________________________________________________
  695.     QTUCopySoundTracks - Copy any sound track from the source movie to the destination movie.
  696.  
  697. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  698.  
  699. aSourceMovie                 movie from which to copy the sound tracks            
  700. aDestinationMovie             movie to which we will copy the sound tracks.    
  701.  
  702. DESCRIPTION
  703.     QTUCopySoundTracks will take any sound tracks from the source movie, and copy these over to the
  704.     destination movie. The destination movie might have no sound track, or then these tracks are 
  705.     added to the existing sound tracks.
  706. */
  707.  
  708. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  709. {
  710.     OSErr     anErr = noErr;
  711.     long        trackCount, index;
  712.     
  713.     DebugAssert(theSrcMovie != NULL); if(theSrcMovie == NULL) return invalidMovie;
  714.     DebugAssert(theDestMovie != NULL); if(theDestMovie == NULL) return invalidMovie;
  715.  
  716.     trackCount = GetMovieTrackCount(theSrcMovie);
  717.     
  718.     // Loop through each track, look for sound tracks.
  719.     for(index = 1; index <= trackCount; index++)
  720.     {
  721.         OSType aTrackType;
  722.         Track    aSrcTrack, aDestTrack;
  723.         Media    aSrcMedia, aDestMedia;
  724.         
  725.         aSrcTrack = GetMovieIndTrack(theSrcMovie, index);            // get next track and media
  726.         aSrcMedia = GetTrackMedia(aSrcTrack);
  727.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  728.         if(anErr != noErr) return anErr;
  729.         
  730.         // try to find sound tracks/media
  731.         GetMediaHandlerDescription(aSrcMedia, &aTrackType, 0, 0);
  732.         if(aTrackType == SoundMediaType)
  733.         {
  734.             // Create the track for the sound media.
  735.             aDestTrack = NewMovieTrack(theDestMovie, 0, 0, GetTrackVolume(aSrcTrack));
  736.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  737.             if(anErr != noErr) return anErr;
  738.             
  739.             // Create a media for the sound track and prepare this media for editing.
  740.             aDestMedia = NewTrackMedia(aDestTrack, SoundMediaType, GetMediaTimeScale(aSrcMedia), 0, 0);
  741.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  742.             if(anErr != noErr) return anErr;
  743.             
  744.             anErr = BeginMediaEdits(aDestMedia); DebugAssert(anErr == noErr);
  745.             if(anErr != noErr) return anErr;
  746.             
  747.             // Insert the new track into the destination movie starting at time zero and
  748.             // lasting for the entire duration of the movie.
  749.             InsertTrackSegment(aSrcTrack, aDestTrack, 0 , GetTrackDuration(aSrcTrack), 0);
  750.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  751.             if(anErr != noErr) return anErr;
  752.             
  753.             // We've done editing the media
  754.             EndMediaEdits(aDestMedia);
  755.         }
  756.     }
  757.     return anErr;
  758. }
  759.  
  760.  
  761.  
  762. /*______________________________________________________________________
  763.     QTUPrintMoviePICT - Print the existing movie frame pict.
  764.  
  765. pascal Boolean QTUPrintMoviePICTr(Movie theMovie, short x, short y,  long PICTUsed)
  766.  
  767. theMovie                    movie that has the poster        
  768. x,y                            starting point coordinates where to place the poster on paper
  769.  
  770. DESCRIPTION
  771.     QTUPrintMoviePICT is a simple function showing how to print movie posters. 
  772.  
  773. ISSUES
  774.     Note that in a real application we should put the PrStlDialog code into the Print Setup… menu
  775.     function. The reason it's inside this function is that we use this code for quick testing of 
  776.     printing.
  777. */
  778.  
  779. pascal OSErr QTUPrintMoviePICT(Movie theMovie, short x, short y, long PICTUsed)
  780. {
  781.     OSErr        anErr = noErr;
  782.     PicHandle     aPictHandle = NULL;
  783.     THPrint        aTHPrint = NULL;
  784.     GrafPtr         aSavedPort;
  785.     TPPrPort    aPrintPort;
  786.     Boolean     aResult;
  787.     Boolean        isPrinting = false;
  788.     Rect            aPictRect;
  789.     
  790.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  791.     
  792.     GetPort(&aSavedPort);
  793.  
  794. // Get the PICT to be printed, either the poster pict or the current frame pict.
  795.     switch(PICTUsed)
  796.     {
  797.         case kPrintFrame:
  798.             aPictHandle = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L));
  799.             break;
  800.             
  801.  
  802.         case kPrintPoster:
  803.             aPictHandle = GetMoviePosterPict(theMovie); 
  804.             break;
  805.  
  806.         default:
  807.             DebugAssert("Should not happen, incorrect constant used"); goto Closure;
  808.     }
  809.  
  810.     if(aPictHandle == NULL) goto Closure;
  811.  
  812.  
  813. // Get the Print record.
  814.     aTHPrint = (THPrint) NewHandleClear(sizeof(TPrint)); DebugAssert(aTHPrint != NULL);
  815.     if(aTHPrint == NULL) goto Closure;
  816.  
  817.     PrOpen(); isPrinting = true;
  818.     anErr = PrError(); DebugAssert(anErr == noErr);
  819.         if(anErr != noErr) goto Closure;
  820.  
  821.     PrintDefault(aTHPrint);
  822.  
  823. // Move this to Print Setup…if you want to make this look really cool.    
  824.     aResult = PrStlDialog(aTHPrint); DebugAssert(aResult == true);
  825.     if(!aResult) goto Closure;
  826.     
  827.     aResult = PrJobDialog(aTHPrint); DebugAssert(aResult == true);
  828.     if(!aResult) goto Closure;
  829.     
  830.     aPrintPort = PrOpenDoc(aTHPrint, NULL, NULL); DebugAssert(aPrintPort != NULL);
  831.     PrOpenPage(aPrintPort, NULL);
  832.     anErr = PrError(); DebugAssert(anErr == noErr);
  833.     if(anErr != noErr) goto Closure;
  834.     
  835. // Print at x,y position
  836.     aPictRect =  (*aPictHandle)->picFrame;
  837.     OffsetRect(&aPictRect, x - aPictRect.left,  y  - aPictRect.top);
  838.     
  839.     DrawPicture(aPictHandle, &aPictRect);
  840.  
  841. // If you want to do additional drawing, do it here.
  842.     
  843.     PrClosePage(aPrintPort);
  844.     PrCloseDoc(aPrintPort);
  845.     anErr = PrError(); DebugAssert(anErr == noErr);
  846.     if(anErr != noErr) goto Closure;
  847.     
  848.     if(( *aTHPrint)->prJob.bJDocLoop == bSpoolLoop)
  849.         PrPicFile(aTHPrint, NULL, NULL, NULL, NULL);
  850.     
  851. // Our closure handling.
  852. Closure:
  853.     SetPort(aSavedPort);
  854.     
  855.     if(isPrinting) PrClose();
  856.     if(aPictHandle) KillPicture(aPictHandle);
  857.     if(aTHPrint) DisposeHandle((Handle)aTHPrint);
  858.     return anErr;
  859. }
  860.  
  861.  
  862. /*______________________________________________________________________
  863.     QTUCalculateMovieMemorySize - Calculate how much memory a movie takes in the app heap.
  864.  
  865. pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize)
  866.  
  867. theMovie                        movie we want to know the size of in the current application heap
  868. theSize                            pointer to a long that will contain the movie size in bytes
  869.  
  870. DESCRIPTION
  871.     QTUCalculateMovieMemorySize will return the amount of bytes it is allocating as a handle
  872.     in the current application heap, if there's not enough space for a temp handle, or if anything
  873.     else fails, the function will return 0L in theSize (and the OSErr).
  874.  
  875. ISSUES
  876.     Note that possible movie controllers associated with the movie and other constructs will eat up
  877.     memory. What you could do is to do a MacsBug HT before the movie or movies are opened, 
  878.     check the amount of free space, and HT after the movies are opened, figure out the movie sizes 
  879.     using the function below, and calculate the delta from these values.
  880. */
  881.  
  882. pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize)
  883. {
  884.     OSErr     anErr = noErr;
  885.     Handle    tempHandle = NULL;
  886.  
  887.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  888.  
  889.     *theSize = 0L;
  890.  
  891.     tempHandle = NewHandle(sizeof(Movie)); DebugAssert(tempHandle != NULL);
  892.     anErr = MemError(); DebugAssert(anErr == noErr);
  893.     if(anErr != noErr || tempHandle == NULL) goto Closure;
  894.  
  895.     anErr =  PutMovieIntoHandle(theMovie, tempHandle); DebugAssert(anErr == noErr);
  896.  
  897.     if(anErr == noErr)    
  898.             *theSize = GetHandleSize(tempHandle);
  899.  
  900. Closure:
  901.     if(tempHandle != NULL) DisposeHandle(tempHandle);
  902.  
  903.     return anErr;
  904. }
  905.  
  906.  
  907. /*______________________________________________________________________
  908.     QTULoadWholeMovieToRAM - Load the entire active segment (movie) into RAM
  909.  
  910. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  911.  
  912. theMovie                        movie we want to know the size of in the current application heap.
  913.  
  914. DESCRIPTION
  915.     QTULoadWholeMovieToRAM is an example of how to load movie information into RAM. In
  916.     this case we will load the entire movie, or in other words all the active segments.
  917.  
  918. ISSUES
  919.     The most likely error returned from this function is due to lack of memory.  You could 
  920.     also fine tune this function by loading partial data based on time or track specifications.
  921.  
  922.     Loading whole movies is OK if the movies are small, have few tracks with little info (text
  923.     tracks, music tracks and so on), there's a certain performance need  why it makes sense 
  924.     to keep the movie in RAM (looping, other issues), and in general if you know why it's needed.
  925. */
  926.  
  927. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  928. {
  929.     OSErr anErr = noErr;
  930.  
  931.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  932.  
  933.     GoToBeginningOfMovie(theMovie);
  934.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  935.     if (anErr != noErr) return anErr;
  936.  
  937.     anErr = LoadMovieIntoRam(theMovie, GetMovieTime(theMovie, NULL), GetMovieDuration(theMovie), 0);
  938.  
  939.     return anErr;
  940. }
  941.  
  942.  
  943. /*______________________________________________________________________
  944.     QTUPlayMovieSound - Play the movie sound track using the Sound Manager.
  945.  
  946. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  947.  
  948. theMovie                        movie wherefrom we extract the sound resource
  949.  
  950. DESCRIPTION
  951.     QTUPlayMovieSound is an example of how to extract the 'snd ' sound resource from the 
  952.     first sound track in a movie, and play this track back using the Sound Manager. This
  953.     sound resource could also be retrieved, or otherwised used in other instances. Note that
  954.     this function is more of an example of how to retrieve sound from a movie; you might
  955.     want to control the start point, duration, and sound track extracted.
  956.  
  957. */
  958.  
  959. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  960. {
  961.     OSErr    anErr = noErr;
  962.     Handle     tempHandle  = NewHandle(1);
  963.     
  964.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  965.  
  966.     // Extract first sound track.
  967.     anErr = PutMovieIntoTypedHandle(theMovie, (Track)0, 'snd ', tempHandle, 0, GetMovieDuration(theMovie),
  968.                                                         0, (ComponentInstance)0); DebugAssert(anErr == noErr);
  969.     if(anErr != noErr) goto Closure;
  970.     anErr = MemError(); DebugAssert(anErr == noErr);
  971.     if(anErr != noErr) goto Closure;
  972.  
  973.     // Play sound resource async.
  974.     anErr = SndPlay(0L, (SndListHandle)tempHandle, true);     DebugAssert(anErr == noErr);
  975.  
  976. Closure:
  977.     if(tempHandle) DisposeHandle(tempHandle);
  978.  
  979.     return anErr;
  980. }
  981.  
  982.  
  983. /*______________________________________________________________________
  984.     QTUDrawVideoFrameAtTime - Display a movie video frame at specified movie time.
  985.  
  986. pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime)
  987.  
  988. theMovie                        movie we are using
  989. atTime                            time value in the movie for the video frame we want to display
  990.  
  991. DESCRIPTION
  992.     QTUDrawVideoFrameAtTime will display a specific video sample (or frame) at a specified time.
  993.     In other words if we want to draw a frame at time point 600, the nearest video frame
  994.     corresponding to this time value will be shown. 
  995.  
  996.     We assume that the movie is properly set, and is using a correct portRect or GWorld.
  997.  
  998. */
  999.  
  1000. pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime)
  1001. {
  1002.     TimeValue totalTime;
  1003.     
  1004.     OSErr anErr = noErr;
  1005.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return paramErr;
  1006.     
  1007.     totalTime = GetMovieDuration(theMovie);
  1008.     if(atTime > totalTime) return paramErr;
  1009.     
  1010.     if(atTime == 0L) {
  1011.         GoToBeginningOfMovie(theMovie); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1012.         if(anErr) goto Closure;
  1013.     }
  1014.     else {
  1015.         SetMovieTimeValue(theMovie, atTime); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1016.         if(anErr) goto Closure;
  1017.     }
  1018.     
  1019.     anErr = UpdateMovie(theMovie);  DebugAssert(anErr == noErr);
  1020.     if(anErr) goto Closure;
  1021.     
  1022.     MoviesTask(theMovie, 0L); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1023.  
  1024. Closure:    
  1025.     return anErr;
  1026. }
  1027.  
  1028.  
  1029.  
  1030. /*______________________________________________________________________
  1031.     QTUScrollToNextVideoSample -  Scroll offscreen from one video sample to the next.
  1032.  
  1033. pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint)
  1034.  
  1035. fromTimePoint                        starting time value of the first video sample (frame)
  1036. toTimePoint                            end time value for the second video sample (frame)
  1037.  
  1038. DESCRIPTION
  1039.     QTUScrollToNextVideoSample will scroll from one video sample to the other one using offscreen
  1040.     GWorlds where the effect is created. 
  1041.  
  1042.     We assume that the movie is properly set, and that the movie will use a proper portRect or GWorld.
  1043.  
  1044. CREDITS
  1045.     Presto Studios for the core idea and some of the code below.
  1046.  
  1047. */
  1048.  
  1049. pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint) 
  1050. {
  1051.     OSErr                 anErr = noErr;
  1052.     GWorldPtr            frameGWorld1 = NULL;
  1053.     GWorldPtr            frameGWorld2 = NULL;
  1054.     PixMapHandle    pixMap1 = NULL;
  1055.     PixMapHandle    pixMap2    = NULL;
  1056.     CGrafPtr            aSavedPort, moviePort;
  1057.     GDHandle            aSavedGDevice, movieGDevice;
  1058.     CTabHandle        colorTable;
  1059.     short                screenDepth = 0;
  1060.     short                screenSize = 0;
  1061.     Rect                    movieRect, sourceRect, destinationRect;
  1062.     RgnHandle            scrollRegion = NULL;
  1063.     RgnHandle            clipRegion = NULL;
  1064.     short                nSteps;
  1065.         
  1066.     DebugAssert(theMovie != NULL); if(theMovie == NULL) goto Closure;
  1067.     
  1068.     //• Store away current portrect and Gdevice, get pixel sizes and color table for GWorld creation purposes.
  1069.     GetGWorld(&aSavedPort, &aSavedGDevice);
  1070.     
  1071.     GetMovieGWorld(theMovie, &moviePort, &movieGDevice);
  1072.     screenDepth = (**(**aSavedGDevice).gdPMap).pixelSize;
  1073.     colorTable = (**(**aSavedGDevice).gdPMap).pmTable;
  1074.     
  1075.     //• Adjust the movie box.
  1076.      GetMovieBox(theMovie, &movieRect);  // If you want to offset by 10,10: OffsetRect(&movieRect, 10 -movieRect.left, 10 - movieRect.top);
  1077.      SetMovieBox(theMovie, &movieRect);
  1078.     
  1079.     //• Create two GWorlds for dual screen writing and possible scrolling transition effects. Lock down pixmaps.
  1080.     anErr = NewGWorld(&frameGWorld1, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr);
  1081.     if(anErr != noErr) goto Closure;
  1082.     anErr = NewGWorld(&frameGWorld2, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr);
  1083.     if(anErr != noErr) goto Closure;
  1084.     
  1085.     pixMap1 = GetGWorldPixMap(frameGWorld1);  if(!LockPixels(pixMap1)) goto Closure;
  1086.     pixMap2 = GetGWorldPixMap(frameGWorld2);  if(!LockPixels(pixMap2)) goto Closure;
  1087.     
  1088.     //• Draw first video sample (frame) to GWorld number 1.
  1089.     SetMovieGWorld(theMovie, frameGWorld1, GetGWorldDevice(frameGWorld1));
  1090.     SetMovieTimeValue(theMovie, fromTimePoint);
  1091.     UpdateMovie(theMovie); MoviesTask(theMovie, 0);
  1092.     
  1093.     //• Draw second video sample (frame) to GWorld number 2.
  1094.     SetMovieGWorld(theMovie, frameGWorld2, GetGWorldDevice(frameGWorld2));
  1095.     SetMovieTimeValue(theMovie, toTimePoint); 
  1096.     UpdateMovie(theMovie); MoviesTask(theMovie, 0);
  1097.     
  1098.     //• Create scroll region and store away the current clip region.
  1099.     scrollRegion = NewRgn(); DebugAssert(scrollRegion != NULL);
  1100.     if(scrollRegion == NULL) goto Closure;
  1101.     
  1102.     clipRegion = NewRgn(); DebugAssert(clipRegion != NULL);
  1103.     if(clipRegion == NULL) goto Closure;
  1104.     GetClip(clipRegion); ClipRect(&movieRect);
  1105.     
  1106.     //• Create the scroll effect.
  1107.     screenSize = movieRect.right - movieRect.left;
  1108.     
  1109.     for(nSteps = 10; nSteps <= screenSize; nSteps += 10)  {
  1110.         SetGWorld( frameGWorld1, NULL);
  1111.         
  1112.         ScrollRect(&movieRect, -10, 0, scrollRegion);
  1113.         SetRect(&sourceRect, movieRect.left, movieRect.top, 
  1114.                 movieRect.left + nSteps, movieRect.bottom);
  1115.         SetRect(&destinationRect, movieRect.right - nSteps,
  1116.                 movieRect.top, movieRect.right, movieRect.bottom);
  1117.         
  1118.         CopyBits( (BitMap *) *pixMap2, (BitMap *) *pixMap1, &sourceRect, &destinationRect,
  1119.                     srcCopy, NULL );                // blit from frameGWorld2 to frameGWorld1
  1120.         DebugAssert(QDError() == noErr);
  1121.         
  1122.         SetGWorld(aSavedPort, aSavedGDevice);
  1123.         CopyBits( (BitMap *) *pixMap1, (BitMap *) &aSavedPort->portPixMap, &movieRect,
  1124.                     &movieRect, srcCopy, NULL );       // blit from frameGWorld1 to screen pixmap
  1125.         DebugAssert(QDError() == noErr);
  1126.     }
  1127.  
  1128.     //• Unlock pixels, restore the original clip region.    
  1129.     UnlockPixels(pixMap1); UnlockPixels(pixMap2);
  1130.     SetClip(clipRegion);
  1131.     
  1132.     //• Closure. Clean up if we have handles.
  1133. Closure:    
  1134.     if(frameGWorld1 != NULL)         DisposeGWorld(frameGWorld1);
  1135.     if(frameGWorld2 != NULL)         DisposeGWorld(frameGWorld2);
  1136.     if(scrollRegion != NULL)             DisposeRgn(scrollRegion);
  1137.     if(clipRegion != NULL)                 DisposeRgn(clipRegion);
  1138.  
  1139.     SetMovieGWorld(theMovie, moviePort, movieGDevice);
  1140.     SetGWorld(aSavedPort, aSavedGDevice);    
  1141.  
  1142.     return anErr;
  1143. }
  1144.  
  1145.  
  1146. /*______________________________________________________________________
  1147.     QTUGetStartPointOfFirstVideoSample -  Get time value of first sample in the movie.
  1148.  
  1149. TimeValue QTUGetStartPointOfFirstVideoSample(Movie theMovie) 
  1150.  
  1151. theMovie                    movie we are interested in
  1152. startPoint                    will contain the value of the start point, if the function fails it will contain
  1153.                                 -1.
  1154.  
  1155. DESCRIPTION
  1156.     QTUGetStartPointOfFirstVideoSample will return the time value of the first video sample found in the
  1157.     movie in the startPoint parameter. If the function fails, startPoint will contain -1 and the OSErr is 
  1158.     also returned.
  1159. */
  1160.  
  1161. pascal OSErr QTUGetStartPointOfFirstVideoSample(Movie theMovie, TimeValue *startPoint) 
  1162. {
  1163.     OSErr    anErr = noErr;
  1164.     OSType    media = VideoMediaType;
  1165.     
  1166.     *startPoint = -1;
  1167.  
  1168.     GetMovieNextInterestingTime(theMovie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0, 
  1169.                                                     fixed1, startPoint, NULL);
  1170.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1171.  
  1172.     return anErr;
  1173. }
  1174.  
  1175.  
  1176. // IMAGE COMPRESSION MANAGER
  1177.  
  1178. /*______________________________________________________________________
  1179.     QTUHasCodecLossLessQuality - Test if a specific codec has a lossless mode in a specific bit depth.
  1180.  
  1181. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  1182.  
  1183. theCodec                        specifies the Codec Type ('jpeg, 'rle ' and so on).
  1184. thePixelDepth                specifies the bit depth (8, 24, 30 and so on). See NIM:QuickTime, page 
  1185.                                     3-70 for more details.
  1186.  
  1187. DESCRIPTION
  1188.     QTUHasCodecLossLessQuality will test if a specific codec has a lossless spatial compression 
  1189.     quality at a certain bit depth. Note that we are not testing the temporal compression qualities.
  1190.  
  1191. EXAMPLE OF USE:
  1192.     if(QTUHasCodecLossLessQuality('jpeg', 32))  
  1193.         printf("JPEG has lossless spatial compression\n");
  1194.     else
  1195.         printf("JPEG has NOT lossless spatial compression\n");
  1196.  
  1197. */
  1198.  
  1199. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  1200. {
  1201.     OSErr     anErr = noErr;
  1202.     CodecQ    aSpatialQuality = codecLosslessQuality;
  1203.  
  1204.     anErr = GetCompressionTime(NULL, NULL, thePixelDepth, theCodec, anyCodec, &aSpatialQuality,
  1205.                         NULL, NULL); DebugAssert(anErr == noErr);
  1206.     
  1207.     if(aSpatialQuality == codecLosslessQuality)    // still the same?
  1208.         return true;
  1209.     else
  1210.         return false;
  1211. }
  1212.  
  1213.  
  1214.  
  1215. // MOVIE CONTROLLER FUNCTIONS
  1216.  
  1217.  
  1218. /*______________________________________________________________________
  1219.     QTUPlayMovieWithMC - Play a specific movie when using movie controllers.
  1220.  
  1221. pascal OSErr QTUPlayMovieWithMC( MovieController mc)
  1222.  
  1223. mc                        specified movie controller to be used
  1224.  
  1225. DESCRIPTION
  1226.     Playmovie will start a movie using a moviecontroller and a specified movie. Note that it also  
  1227.     does a preroll of the movie for performance reasons. 
  1228.  
  1229. */
  1230.  
  1231. pascal OSErr QTUPlayMovieWithMC(MovieController mc)
  1232. {
  1233. // Play normal speed forward, taking into account the possibility 
  1234. // of a movie with a nonstandard PreferredRate.
  1235.     OSErr    anErr = noErr;
  1236.     Fixed     aRate;
  1237.     Movie    aMovie;
  1238.  
  1239.     aMovie = MCGetMovie(mc);
  1240.  
  1241.     aRate= GetMoviePreferredRate(aMovie);
  1242.     anErr = QTUPrerollMovie(aMovie);  // Important: Preroll the movie here.
  1243.     DebugAssert(anErr == noErr);
  1244.  
  1245.     if(anErr == noErr)
  1246.     {
  1247.         MCDoAction(mc, mcActionPlay, (void *)aRate);  // note last value
  1248.     }
  1249.     
  1250.     return anErr;
  1251. }
  1252.  
  1253.  
  1254. /*______________________________________________________________________
  1255.     QTUDoIgnoreMCDrags - Disable Drag and Drop facilities of the movie controller environment.
  1256.  
  1257. pascal OSErr  QTUDoIgnoreMCDrags(MovieController  mc)
  1258.  
  1259. mc                        is the specified moviecontroller to be used
  1260.  
  1261. DESCRIPTION
  1262.     QTUDoIgnoreMCDrags will ensure that the Drag and Drop functionality is not handled within 
  1263.     the movie specified by the movie controller.
  1264.  
  1265. ISSUES
  1266.     Note that this is a workaround in QT 2.0 (test for QT 2.0 or higher if you want to use
  1267.     the drag-and-drop support in QT), and this function might not be needed in later QT versions.
  1268. */
  1269.  
  1270. pascal OSErr QTUDoIgnoreMCDrags(MovieController  mc)
  1271. {
  1272.    OSErr           anErr = noErr;
  1273.    GWorldPtr  aTempGWorld;
  1274.    Rect             aTempRect = {0, 0, 20, 20};
  1275.    CGrafPtr     aPort;
  1276.  
  1277.    // First create a 1-bit small 20x20 offscreen.
  1278.    anErr = NewGWorld( &aTempGWorld, 1, &aTempRect, NULL, NULL, 0L );
  1279.    DebugAssert(anErr == noErr);
  1280.  
  1281.    if (anErr != noErr)
  1282.    {
  1283.            aPort = MCGetControllerPort(mc);                                    // get the current port
  1284.            MCSetControllerPort(mc, (CGrafPtr)aTempGWorld );        // set mc port to new offscreen
  1285.            MCDoAction(mc, mcActionSetDragEnabled, (void *)false); // don't want dragging
  1286.           MCSetControllerPort(mc, aPort);                                        // restore mc port
  1287.            DisposeGWorld(aTempGWorld);                                            // dispose offscreen
  1288.    }
  1289.    return anErr;
  1290. }
  1291.  
  1292.  
  1293. /*______________________________________________________________________
  1294.     QTUPointInMC - Test if a point is placed in the movie controller rect area or not.
  1295.  
  1296. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1297.  
  1298. mc                            is the specified moviecontroller to be used
  1299. theWindow                window used for testing for the hit point
  1300. where                        hit point
  1301.  
  1302. DESCRIPTION
  1303.     QTUPointInMC is a simple test to check where the mouse was clicked inside the window
  1304.     with a movie controller, returns true of the mouse click was inside the movie controller
  1305.     rect. See Peter Hoddie's article in develop# 18 for more details (code is from him as well).
  1306. */
  1307.  
  1308. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1309. {
  1310.     RgnHandle        aRegion;
  1311.     Boolean            result = false;
  1312.     
  1313.     aRegion = MCGetWindowRgn(mc, theWindow);
  1314.        DebugAssert(aRegion != NULL);
  1315.     
  1316.     if(aRegion != NULL)
  1317.     {
  1318.         result = PtInRgn(where, aRegion);
  1319.         DisposeRgn(aRegion);
  1320.     }
  1321.     
  1322.     return result;
  1323. }
  1324.  
  1325.  
  1326. /*______________________________________________________________________
  1327.     QTUSelectAllMovie - Select the whole movie time duration with the controller.
  1328.  
  1329. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1330.  
  1331. mc                        is the specified moviecontroller to be used
  1332.  
  1333. DESCRIPTION
  1334.     QTUSelectAllMovie is an example how to select the whole movie duration using the movie
  1335.     controller, this function could be used for Select All menu entries and similar cases.
  1336. */
  1337.  
  1338. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1339. {
  1340.     OSErr             anErr = noErr;
  1341.     TimeRecord  aTimeRecord;
  1342.     Movie             aMovie = NULL;
  1343.     
  1344.     DebugAssert(mc != NULL);
  1345.     if(mc == NULL) return paramErr;
  1346.     
  1347.     aMovie = MCGetMovie(mc); DebugAssert(aMovie != NULL);
  1348.     if(aMovie == NULL) return paramErr;
  1349.     
  1350.     aTimeRecord.value.hi = 0;
  1351.     aTimeRecord.value.lo = 0;
  1352.     aTimeRecord.base = 0;
  1353.     
  1354.     aTimeRecord.scale = GetMovieTimeScale(aMovie);
  1355.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1356.     if(anErr != noErr) return anErr;
  1357.     
  1358.     anErr = MCDoAction(mc, mcActionSetSelectionBegin, &aTimeRecord);
  1359.     DebugAssert(anErr == noErr);
  1360.     if(anErr != noErr) return anErr;
  1361.     
  1362.     aTimeRecord.value.lo = GetMovieDuration(aMovie);
  1363.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1364.     if(anErr != noErr) return anErr;
  1365.     
  1366.     anErr = MCDoAction(mc, mcActionSetSelectionDuration, &aTimeRecord);
  1367.     DebugAssert(anErr == noErr);
  1368.     
  1369.     return anErr;
  1370. }
  1371.  
  1372.  
  1373. /*______________________________________________________________________
  1374.      QTUResizeMCActionFilter - Example of a movie controller filter that will resize the window 
  1375.     where the movie is placed when the controllers themself change. 
  1376.  
  1377. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void *params, long refCon)
  1378.  
  1379. mc                            specified moviecontroller to be used.
  1380. action                        the action for the mc action filter
  1381. params                        parameters passed with the action
  1382. refCon                      additional long word that could be used for all kinds of purposes
  1383.  
  1384. DESCRIPTION
  1385.     QTUResizeMCActionFilter is an example of how to create a nice movie controller filter that 
  1386.     will handle resizing of the window with the movie, and this will happen every time the controllers
  1387.     themselves change. It's also an example of how to write other kinds of movie controller filters.
  1388. */
  1389.  
  1390. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void* /*params*/ , long refCon)
  1391. {
  1392.     Rect aMovieBounds;
  1393.     
  1394.     switch(action)
  1395.     {
  1396.         case mcActionControllerSizeChanged:
  1397.             MCGetControllerBoundsRect(mc, &aMovieBounds);
  1398.             SizeWindow((WindowPtr) refCon, aMovieBounds.right - aMovieBounds.left,
  1399.                                 aMovieBounds.bottom - aMovieBounds.top, true);
  1400.             break;
  1401.     }
  1402.         return false;
  1403. }
  1404.  
  1405.  
  1406. /*______________________________________________________________________
  1407.     QTUResizeMCWindow - Resize a window to either normal size, double size or  half of the movie rect size.
  1408.  
  1409. pascal Boolean QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1410.  
  1411. mc                                specified moviecontroller to be used
  1412. theWindow                    window that will be resized
  1413. theMovieSize                constant that defines what default size we are interested in,  kNormalSize, kHalfSize, kDoubleSize
  1414. originalSize                    the original size of the movie, we need to keep track of this one in order to handle the 
  1415.                                      ambient new sizes (half, double, normal).
  1416.  
  1417. DESCRIPTION
  1418.     QTUResizeMCWindow is an example of a function how to resize the movie window with the controllers.
  1419.     The most common cases is half size, normal size or double size. But nothing hinders to add more sizes
  1420.     into this function. Note that if the movie window is doubled, we will get pixel-doubling by the QuickTime
  1421.     engine.
  1422. */
  1423.  
  1424. pascal OSErr QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1425. {
  1426.     OSErr         anErr = noErr;
  1427.     Rect             aMovieBounds;
  1428.     GrafPtr     aSavedPort;
  1429.     
  1430.     DebugAssert(mc != NULL); if(mc == NULL) return paramErr;
  1431.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1432.     
  1433.     GetPort(&aSavedPort);
  1434.     SetPort((GrafPtr)theWindow);
  1435.     
  1436.     aMovieBounds.top = 0; aMovieBounds.left = 0;
  1437.  
  1438.     switch(theMovieSize)
  1439.     {
  1440.         case kNormalMovieSize:
  1441.                 MCSetControllerBoundsRect(mc, &originalSize);
  1442.                 SizeWindow(theWindow, originalSize.right, originalSize.bottom, true);
  1443.             break;
  1444.         
  1445.         case kHalfMovieSize:
  1446.                 aMovieBounds.right = (originalSize.right - originalSize.left) / 2;
  1447.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) / 2;
  1448.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1449.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1450.             break;
  1451.         
  1452.         case kDoubleMovieSize:
  1453.                 aMovieBounds.right = (originalSize.right - originalSize.left) * 2;
  1454.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) * 2;
  1455.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1456.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1457.             break;
  1458.         
  1459.         default:
  1460.             SetPort(aSavedPort);
  1461.             anErr = paramErr;
  1462.     }
  1463.     
  1464.     SetPort(aSavedPort);
  1465.     return anErr;
  1466. }
  1467.  
  1468.  
  1469. /*______________________________________________________________________
  1470.     QTUResizeMCWindow -Change the movie rate using the movie controller. 
  1471.  
  1472. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1473.  
  1474. mc                            specified moviecontroller to be used
  1475. theRate                        new rate value, we are using specific constants, see the eQTUMovieRates enum
  1476.                                 in the DTSQTUtilities.h file concerning the values.
  1477.  
  1478. DESCRIPTION
  1479.     QTUMCSetMovieRate will use an existing movie controller and change the rate. This is a very 
  1480.     simple function, but we do have a list of constants that shows the various values that could be used 
  1481.     (eQTUMovieRates, DTSQTUtilities.h), and also it shows that if the rate changes from 0 to something 
  1482.     else, then we need to preroll the movie. The Apple MM Tuner will make sure the movie is prerolled,
  1483.     but we can't assume that every Mac has this extension installed, that's why it's still very important
  1484.     to preroll.
  1485.     
  1486. ISSUES
  1487.     Note that movies have stored preferred rates, so if you want to compensate for this factor you need
  1488.     to read in this value as well before setting a double or half speed value.
  1489. */
  1490.  
  1491. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1492. {
  1493.     OSErr     anErr = noErr;
  1494.     Fixed     aRate;
  1495.     
  1496.     DebugAssert(mc != NULL);  
  1497.     if(mc == NULL)
  1498.     {
  1499.         anErr = paramErr; goto Closure;
  1500.     }
  1501.     
  1502.     // Test if the playrate changes from 0 to a non-zero value, if so then preroll the movie.
  1503.     MCDoAction(mc, mcActionGetPlayRate, &aRate);
  1504.     if( (aRate == 0) && (theRate != 0) )
  1505.     {
  1506.         anErr = QTUPrerollMovie(MCGetMovie(mc));            // we are using the DTSQTUtilities function
  1507.         DebugAssert(anErr == noErr);
  1508.         if(anErr != noErr) return anErr;
  1509.     }
  1510.         
  1511.     anErr = MCDoAction(mc, mcActionPlay, (Ptr) theRate); DebugAssert(anErr == noErr);
  1512.  
  1513. Closure:    
  1514.     return anErr;
  1515. }
  1516.  
  1517. // SEQUENCE GRABBER FUNCTIONS
  1518. /*______________________________________________________________________
  1519.     QTUCreateSequenceGrabber - Create an instance of a sequence grabber for specified window.
  1520.  
  1521. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1522.  
  1523. theWindow                    window where the sequence grabber will operate
  1524.  
  1525. DESCRIPTION
  1526.     QTUCreateSequenceGrabber will try to open the default sequence grabber component and 
  1527.     make sure this component will work in the GWorld of a specified window. 
  1528.  
  1529.     If we don't find a suitable sequence grabber, or if we encounter problems, we will return NULL.
  1530. */
  1531.  
  1532.  
  1533. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1534. {
  1535.     OSErr anErr = noErr;
  1536.     SeqGrabComponent s = NULL;
  1537.  
  1538.     DebugAssert(theWindow != NULL); if(theWindow == NULL) goto Closure;
  1539.  
  1540.     s = OpenDefaultComponent(SeqGrabComponentType, 0);
  1541.  
  1542.     if(s) // we got a valid one
  1543.     {
  1544.         anErr = SGInitialize(s); DebugAssert(anErr == noErr);
  1545.         if(anErr != noErr) goto Closure;
  1546.  
  1547.         anErr = SGSetGWorld(s, (CGrafPtr)theWindow, NULL); DebugAssert(anErr == noErr);
  1548.         if(anErr != noErr) goto Closure;
  1549.     }
  1550.  
  1551.     return s;
  1552. Closure:
  1553.     return NULL;
  1554. }
  1555.  
  1556. /*______________________________________________________________________
  1557.     QTUCreateSGGrabChannels - Create SG channels, video and audio.
  1558.  
  1559. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1560.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1561.  
  1562. s                            current active sequence grabber component instance
  1563. theBounds                the size of the video channel sequence grabber area
  1564. theUsage                any additional flags for the video SG
  1565. theVideoChannel    pointer to the video channel we will receive
  1566. theSoundChannel    pointer to the audio channel we will receive
  1567.  
  1568.  
  1569. DESCRIPTION
  1570.     QTUCreateSGGrabChannels will create video and audio SG channels (SGChannels) using the specified
  1571.     default SG component.
  1572.  
  1573. ISSUES
  1574.     We will terminate whenever we can't properly create  a channel (sound, audio), if you still want to
  1575.     retrieve a valid channel (let's say the sound one is OK while the we can't open an audio one), you
  1576.     could slightly rewrite this code.
  1577. */
  1578.  
  1579. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1580.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1581. {
  1582.     OSErr     anErr = noErr;
  1583.     long        sgUsage = seqGrabPreview;    // default at least this flag    
  1584.  
  1585.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1586.  
  1587.     sgUsage |= theUsage;                        // add any other usage flag info now
  1588.  
  1589.     // Create Video Channel.
  1590.     anErr = SGNewChannel(s, VideoMediaType, theVideoChannel); DebugAssert(anErr == noErr);
  1591.     if(anErr != noErr) goto FailureHandling;
  1592.     
  1593.     anErr = SGSetChannelBounds(*theVideoChannel, theBounds); DebugAssert(anErr == noErr);
  1594.     if(anErr != noErr) goto FailureHandling;
  1595.  
  1596.     anErr = SGSetChannelUsage(*theVideoChannel, sgUsage); DebugAssert(anErr == noErr);
  1597.     if(anErr != noErr) goto FailureHandling;
  1598.  
  1599.     // Create Sound Channel.
  1600.     anErr = SGNewChannel(s, SoundMediaType, theSoundChannel); DebugAssert(anErr == noErr);
  1601.     if(anErr != noErr) goto FailureHandling;
  1602.  
  1603.     anErr = SGSetChannelUsage(*theSoundChannel, sgUsage); DebugAssert(anErr == noErr);
  1604.     if(anErr != noErr) goto FailureHandling;
  1605.  
  1606.  
  1607.     return anErr;
  1608.  
  1609. FailureHandling:
  1610.     SGDisposeChannel(s, *theVideoChannel); *theVideoChannel = NULL;
  1611.     SGDisposeChannel(s, *theSoundChannel); *theSoundChannel = NULL;
  1612.  
  1613.     return anErr;
  1614. }
  1615.  
  1616.  
  1617. /*______________________________________________________________________
  1618.     QTUDoesVDIGReceiveVideo - Test if vdig receives a live incoming video signal.
  1619.  
  1620. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1621.  
  1622. s                    our sequence grabber component instance
  1623.  
  1624. DESCRIPTION
  1625.     QTUDoesVDIGReceiveVideo test if the currently active vdig is receiving an incoming, live 
  1626.     video signal. We assume that all well behaved vdigs set the digiInSignalLock flag.
  1627.  
  1628. */
  1629. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1630. {
  1631.     OSErr        anErr = noErr;
  1632.     long            inputFlags, outFlags;
  1633.  
  1634.     DebugAssert(s != NULL); if(s == NULL) goto Closure;
  1635.  
  1636.     anErr = VDGetCurrentFlags(s, &inputFlags, &outFlags); DebugAssert(anErr == noErr);
  1637.     if(anErr != noErr) goto Closure;
  1638.  
  1639.     if(inputFlags & digiInSignalLock)
  1640.         return true;
  1641.  
  1642. Closure:
  1643.     return false;
  1644. }
  1645.  
  1646.  
  1647. /*______________________________________________________________________
  1648.     QTUChangeSGWindowSize - Change window size of the video sequence grabber window.
  1649.  
  1650. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, 
  1651.                             WindowPtr theWindow, long width, long height)
  1652.  
  1653. s                    our sequence grabber component instance
  1654. videoChannel    the specified (currently used) video channel
  1655. theWindow    window used for the digitizing sequence
  1656. width            new width of the digitizer rect
  1657. height            new height of the digitizer rect
  1658.  
  1659. DESCRIPTION
  1660.     QTUChangeSGWindowSize shows how to change the window size for the current digitizing sequence
  1661.     taking place in the window. This is more of an example function as there might be other issues
  1662.     to be taken into account (such as preference settings and similar issues) while changing the
  1663.     bounds of the digitizing rect.
  1664.  
  1665. */
  1666.  
  1667. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, WindowPtr theWindow, long width, long height)
  1668. {
  1669.     OSErr                                 anErr = noErr;
  1670.  
  1671.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1672.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1673.     DebugAssert(videoChannel != NULL); if(videoChannel == NULL) return badSGChannel;
  1674.  
  1675.     anErr = SGPause(s, true); DebugAssert(anErr == noErr); if(anErr != noErr) goto Closure;
  1676.  
  1677.     SizeWindow(theWindow, width, height, false);
  1678.     
  1679.     anErr = SGSetChannelBounds(videoChannel, &theWindow->portRect); DebugAssert(anErr == noErr);
  1680.     if(anErr != noErr) goto Closure;
  1681.  
  1682.     anErr = SGPause(s, false); DebugAssert(anErr == noErr); 
  1683.  
  1684. Closure:
  1685.     return anErr;
  1686. }
  1687.  
  1688.  
  1689.  
  1690. // COMPONENT FUNCTIONS
  1691.  
  1692. /*______________________________________________________________________
  1693.     QTUDoGetComponent - Get a specific component based on component type and component sub-type.
  1694.  
  1695. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1696.  
  1697. theComponentType                    the component type we are interested in
  1698. theSpecificComponent                the specific component sub-type we are interested int
  1699.  
  1700. DESCRIPTION
  1701.     QTUDoGetComponent will get a specific component based on the component type and sub-type.  We have 
  1702.     special code for particular components (for instance movieImporttype and movieExporttype), so
  1703.     if we specify such types, the function will narrow down the search further for the right components.
  1704.     
  1705.     The specificComponent is just the special component we want to search for, if the component type is 
  1706.     NULL, then the Specific component is the one and only we are interested in. Note that we don't care 
  1707.     about the manufacturer information in this function. 
  1708.     
  1709.     If we don't find a suitable component we will return NULL.
  1710. */
  1711.  
  1712. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1713. {
  1714.     ComponentDescription     aCD;
  1715.     Component                     aComponent = NULL;
  1716.     
  1717.     aCD.componentType = theComponentType;
  1718.     aCD.componentSubType = theSpecificComponent;
  1719.     aCD.componentManufacturer = 0;
  1720.     
  1721.     // The following code is inserted for special handling of some known cases.
  1722.     if(theComponentType == MovieImportType)
  1723.     {
  1724.         aCD.componentFlags = canMovieImportFiles;
  1725.         aCD.componentFlagsMask = canMovieImportFiles;
  1726.     }
  1727.     else if(theComponentType == MovieExportType)
  1728.     {
  1729.         aCD.componentFlags = canMovieExportFiles;
  1730.         aCD.componentFlagsMask = canMovieExportFiles;
  1731.     }
  1732.  
  1733.     // OK, get the component.
  1734.     aComponent = FindNextComponent((Component)0, &aCD);
  1735.     
  1736.     return aComponent;
  1737. }
  1738.  
  1739.  
  1740. /*______________________________________________________________________
  1741.     QTUHasComponentType -Query for a specific component based on component type and 
  1742.     component sub-type.
  1743.  
  1744. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1745.  
  1746. theComponentType                    the component type we are interested in
  1747. theSpecificComponent                the specific component sub-type we are interested int
  1748.  
  1749. DESCRIPTION
  1750.     QTUDoGetComponent will query for a specific component based on the component type and sub-type.  
  1751.     We have special code for particular components (for instance movieImporttype and movieExporttype),
  1752.     so if we query for such types, the function will narrow down the search further for the right 
  1753.     components.
  1754.     
  1755.     The specificComponent is just the special component we want to search for, if the component 
  1756.     type is NULL, then the Specific component is the one and only we are interested in. Note that we 
  1757.     don't care about the manufacturer information in this function. 
  1758.     
  1759.     If we don't find a suitable component we will return false, otherwise we will return true.
  1760. */
  1761.  
  1762. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1763. {
  1764.     ComponentDescription aCD;
  1765.     
  1766.     aCD.componentType = theComponentType;
  1767.     aCD.componentSubType = theSpecificComponent;
  1768.     aCD.componentManufacturer = 0;
  1769.     
  1770.     if(theComponentType == MovieImportType)
  1771.     {
  1772.         aCD.componentFlags = canMovieImportFiles;
  1773.         aCD.componentFlagsMask = canMovieImportFiles;
  1774.     }
  1775.     else if(theComponentType == MovieExportType)
  1776.     {
  1777.         aCD.componentFlags = canMovieExportFiles;
  1778.         aCD.componentFlagsMask = canMovieExportFiles;
  1779.     }
  1780.  
  1781.     if(FindNextComponent((Component)0, &aCD) != NULL)
  1782.         return true;
  1783.     else
  1784.         return false;
  1785. }
  1786.  
  1787.  
  1788. //______________________________________________________________________
  1789. // T H E    E N D